﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;

namespace Restful_Api.Controllers
{
    [ApiController]
    [Route("api/User")]
    public class OAuthController : ControllerBase
    {
        private readonly IAuthenticateService _authService;

        public OAuthController(IAuthenticateService authService)
        {
            _authService = authService;
        }

        [AllowAnonymous]
        [HttpPost, Route("requestToken")]
        //生成token
        public ActionResult RequestToken([FromBody] LoginRequestDTO request)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest("无效的请求");
            }
            if (_authService.IsAuthenticated(request, out string token))
            {
                return Ok(token);
            }
            return BadRequest("无效的请求");
        }
        [AllowAnonymous]
        [HttpGet]
        public ActionResult GetTokenInfo([FromHeader(Name = "Authorization")]string accesTocken)
        {
            var result = _authService.GetTockenInfo(accesTocken);
            return Ok(result);
        }

    }
    /// <summary>
    /// 对应在appsetting.json里的自定义配置
    /// 用来存储签发或者验证jwt时用到的信息
    /// </summary>
    public class TokenManagement
    {
        [JsonProperty("secret")]
        public string Secret { get; set; }//密钥

        [JsonProperty("issuer")]
        public string Issuer { get; set; }//发行商

        [JsonProperty("audience")]
        public string Audience { get; set; }//受众

        [JsonProperty("accessExpiration")]
        public int AccessExpiration { get; set; }//访问过期

        [JsonProperty("refreshExpiration")]
        public int RefreshExpiration { get; set; }//刷新过期
    }
    public class LoginRequestDTO
    {
        [Required]
        [JsonProperty("username")]
        public string Username { get; set; }

        [Required]
        [JsonProperty("password")]
        public string Password { get; set; }
    }
    public interface IAuthenticateService
    {
        bool IsAuthenticated(LoginRequestDTO request, out string token);//生成token
        LoginRequestDTO GetTockenInfo(string accesTocken);//解析token
    }
    public class TokenAuthenticationService : IAuthenticateService
    {
        private readonly IUserService _userService;
        private readonly TokenManagement _tokenManagement;

        public TokenAuthenticationService(IUserService userService, IOptions<TokenManagement> tokenManagement)
        {
            _userService = userService;
            _tokenManagement = tokenManagement.Value;
        }

        public LoginRequestDTO GetTockenInfo(string accesTocken)
        {
            try
            {
                if (accesTocken.Contains("Bearer")) //防止前端传过来的tocken 去除 Bearer 的字符串                
                    accesTocken = accesTocken.Replace("Bearer ", "");

                var tockHandler = new JwtSecurityToken(accesTocken);
                LoginRequestDTO loginRequestDTO = new LoginRequestDTO()
                {
                    Username = tockHandler.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Name).Value
                };
                return loginRequestDTO;
            }
            catch (Exception ex)
            {
                throw new Exception("解析token错误");
            }
        }

        public bool IsAuthenticated(LoginRequestDTO request, out string token)
        {
            token = string.Empty;
            if (!_userService.IsValid(request))
                return false;
            var claims = new[] { new Claim(ClaimTypes.Name, request.Username) };
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_tokenManagement.Secret));
            var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var jwtToken = new JwtSecurityToken(
                _tokenManagement.Issuer,
                _tokenManagement.Audience,
                claims,
                expires: DateTime.Now.AddSeconds(_tokenManagement.AccessExpiration),//设置过期时间            
                signingCredentials: credentials);

            token = new JwtSecurityTokenHandler().WriteToken(jwtToken);

            return true;

        }
    }
    public interface IUserService
    {
        bool IsValid(LoginRequestDTO req);
    }
    public class UserService : IUserService
    {
        //模拟测试，默认都是人为验证有效
        public bool IsValid(LoginRequestDTO req)
        {
            return true;
        }
    }
}
